﻿using BunnyEater.Common.Extensions;
using BunnyEater.Common.Jwt;
using BunnyEater.Common.Jwt.Dto;
using BunnyEater.Common.ResponseOutput;
using BunnyEater.Domain.Base;
using BunnyEater.Domain.SystemManagement;
using BunnyEater.EntityFrameworkCore;
using BunnyEater.Repository.BaseRepository;
using BunnyEater.Repository.Extensions;
using BunnyEater.Service.SystemManagementService.UserService.Dto;
using Microsoft.AspNet.Identity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using PasswordVerificationResult = Microsoft.AspNet.Identity.PasswordVerificationResult;
using System.Linq.Expressions;
using BunnyEater.Common.Config.Dto;

namespace BunnyEater.Service.SystemManagementService.UserService
{
    public class UsersService : IUsersService
    {

        protected BunnyEaterContext _bunnyEaterContext;
        private readonly IRepository<User> _userRepository;
        private readonly ILogger<UsersService> _logger;
        private readonly IPasswordHasher<User> _passwordHasher;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IRepository<UserRole> _userRoleRepository;
        private readonly IRepository<Role> _roleRepository;
        private readonly IRepository<RolePermissions> _rolePermissionsRepository;
        private readonly IRepository<Permissions> _permissionsRepository;


        public UsersService(BunnyEaterContext bunnyEaterContext
            , IRepository<User> userRepository
            , ILogger<UsersService> logger
            , IPasswordHasher<User> passwordHasher
            , IHttpContextAccessor httpContextAccessor
            , IRepository<UserRole> userRoleRepository
            , IRepository<Role> roleRepository
            , IRepository<RolePermissions> rolePermissionsRepository
            , IRepository<Permissions> permissionsRepository)
        {
            _bunnyEaterContext = bunnyEaterContext;
            _userRepository = userRepository;
            _logger = logger;
            _passwordHasher = passwordHasher;
            _httpContextAccessor = httpContextAccessor;
            _userRoleRepository = userRoleRepository;
            _roleRepository = roleRepository;
            _rolePermissionsRepository = rolePermissionsRepository;
            _permissionsRepository = permissionsRepository;
        }

        #region 查询

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="loginRequest">用户信息请求体</param>
        /// <returns></returns>
        public async Task<ResponseReturnsEntity<LoginRequest>> Login(LoginRequest loginRequest)
        {

            var account = loginRequest.Account;
            var password = loginRequest.Password;
            var message = "";
            try
            {
                //1. 非空
                if (string.IsNullOrEmpty(account) || string.IsNullOrEmpty(password))
                {
                    message = "账号和密码均不能为空！";
                    _logger.LogInformation(message);
                    return ResponseReturnsEntity<LoginRequest>.Fail(message);
                }

                //2. 获取登录账号信息
                var userEntity = await _userRepository.GetUserForLoginAsync(account);

                //账号验证
                if (userEntity == null)
                {
                    //记录警告但不透露具体是用户名还是密码
                    message = $"【{DateTime.Now}】登录失败，账号【{account}】不存在";
                    _logger.LogWarning(message);
                    return ResponseReturnsEntity<LoginRequest>.Fail(message);
                }

                //3.`密码验证
                var result = _passwordHasher.VerifyHashedPassword(userEntity, userEntity.Password, loginRequest.Password);
                if (result.Equals(PasswordVerificationResult.Failed))
                {
                    message = $"【{DateTime.Now}】登录失败，账号【{account}】密码错误";
                    _logger.LogWarning(message);
                    return ResponseReturnsEntity<LoginRequest>.Fail(message);
                }
                // 4. 处理需要重新哈希的情况
                if (result.Equals(PasswordVerificationResult.SuccessRehashNeeded))
                {
                    userEntity.Password = _passwordHasher.HashPassword(userEntity, loginRequest.Password);
                    await _userRepository.UpdateEntityAsync(userEntity);
                    _logger.LogInformation($"用户 {userEntity.Id} 密码哈希已更新");
                }

                // 5. 更新最后登录时间
                userEntity.LastLoginAt = DateTime.Now;
                userEntity.IsOnLine = true;
                // 6. 生成令牌
                loginRequest.Id = userEntity.Id;
                //loginRequest.Password = userEntity.Password;
                var token = GetAccountToken(TokenType.AccountToken, loginRequest);
                var refreshToken = GetAccountToken(TokenType.RefreshToken, loginRequest);
                // 创建 ClaimsIdentity 并设置 User
                //将用户信息存入 HttpContext.User
                //读取token的Claims
                var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
                var identity = new ClaimsIdentity(jwtToken.Claims, "JWT");
                _httpContextAccessor.HttpContext.User = new ClaimsPrincipal(identity);
                await _userRepository.UpdateEntityAsync(userEntity);

                var nowUserEntity = userEntity.Mapto<LoginRequest>();
                return ResponseReturnsEntity<LoginRequest>.Success(nowUserEntity, token, refreshToken);
            }
            catch (Exception ex)
            {
                message = $"【{DateTime.Now}】登录过程出错，错误信息：【{ex.Message}】";
                _logger.LogError(message);
                return ResponseReturnsEntity<LoginRequest>.Fail(message);
            }

        }

        /// <summary>
        /// 获取Token令牌
        /// </summary>
        /// <param name="tokenType"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public string GetAccountToken(TokenType tokenType, LoginRequest user)
        {
            var userMap = new UserDto
            {
                Id = user.Id,
                Account = user.Account,
                Password = user.Password,
            };
            var claims = JwtHelper.CreateClaims(tokenType, userMap);
            string jwtToken = JwtHelper.GenerateToken(tokenType, claims);
            return jwtToken;
        }

        /// <summary>
        /// 主键获取用户
        /// </summary>
        public async Task<ResponseReturnsEntity<User>> GetUserById(string id)
        {
            var user = new User() { Id = id };
            var result = await _userRepository.GetEntityByIdAsync(user);
            return ResponseReturnsEntity<User>.Success(result);
        }

        /// <summary>
        /// 获取用户详情（包含角色信息）
        /// </summary>
        /// <param name="id">用户Id</param>
        /// <returns>用户详情</returns>
        public async Task<ResponseReturnsEntity<UserDetailDto>> GetUserDetailById(string id)
        {
            try
            {
                // 参数校验
                if (string.IsNullOrEmpty(id))
                {
                    return ResponseReturnsEntity<UserDetailDto>.Fail("用户ID不能为空");
                }

                // 获取用户信息
                var user = await _userRepository.GetEntityByIdAsync(new User { Id = id });
                if (user == null)
                {
                    return ResponseReturnsEntity<UserDetailDto>.Fail("用户不存在");
                }

                // 查询用户角色关联
                var userRoles = _userRoleRepository.GetListQuery()
                    .Where(ur => ur.UserId == id)
                    .ToList();

                // 获取角色ID列表
                var roleIds = userRoles.Select(ur => ur.RoleId).ToList();

                // 查询角色信息
                var roles = _roleRepository.GetListQuery()
                    .Where(r => roleIds.Contains(r.Id))
                    .ToList();

                // 构建角色列表
                var roleList = roles.Select(r => new RoleDto
                {
                    RoleId = r.Id,
                    RoleName = r.RoleNmae
                }).ToList();

                // 构建用户详情DTO
                var userDetail = new UserDetailDto
                {
                    Id = user.Id,
                    Account = user.Account,
                    UserName = user.UserName,
                    NickName = user.NickName,
                    UserGender = user.UserGender,
                    MobilePhoneNumber = user.MobilePhoneNumber,
                    Telephone = user.Telephone,
                    Birthday = user.Birthday,
                    Email = user.Email,
                    DeptId = user.DeptId,
                    EmployeeNumber = user.EmployeeNumber,
                    IsOnLine = user.IsOnLine,
                    State = user.State,
                    LastLoginAt = user.LastLoginAt,
                    CreateTime = user.CreateTime,
                    ModifyTime = user.ModifyTime,
                    Password = "******",
                    Roles = roleList
                };

                return ResponseReturnsEntity<UserDetailDto>.Success(userDetail);
            }
            catch (Exception ex)
            {
                _logger.LogError($"获取用户详情失败: {ex.Message}");
                return ResponseReturnsEntity<UserDetailDto>.Fail($"获取用户详情失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 分页查询用户列表，包含用户角色信息
        /// </summary>
        /// <param name="query">分页查询参数</param>
        /// <returns>分页用户列表</returns>
        public async Task<ResponseReturnsEntity<Page<UserListDto>>> GetPagedUsersAsync(UserPagedQueryDto query)
        {
            try
            {
                // 基础条件：未删除
                var users = _userRepository.GetListQuery().Where(u => !u.IsDelete);

                // SearchKeyword不为空时，增加模糊查询
                if (!string.IsNullOrEmpty(query.SearchKeyword))
                {
                    users = users.Where(u =>
                        EF.Functions.Like(u.UserName, $"%{query.SearchKeyword}%") ||
                        EF.Functions.Like(u.NickName, $"%{query.SearchKeyword}%") ||
                        EF.Functions.Like(u.Account, $"%{query.SearchKeyword}%") ||
                        EF.Functions.Like(u.MobilePhoneNumber, $"%{query.SearchKeyword}%") ||
                        EF.Functions.Like(u.Email, $"%{query.SearchKeyword}%")
                    );
                }

                // State不为空时，增加状态等于判断
                if (query.State.HasValue)
                {
                    users = users.Where(u => u.State == query.State.Value);
                }

                // 调用扩展方法分页，按创建时间倒序
                var result = await users.ToPagedListAsync(
                    query.PageIndex,
                    query.PageSize,
                    null,
                    u => u.CreateTime,
                    false);

                // 获取所有用户ID
                var userIds = result.Items.Select(u => u.Id).ToList();

                // 查询用户角色关联
                var userRoles = _userRoleRepository.GetListQuery()
                    .Where(ur => userIds.Contains(ur.UserId))
                    .ToList();

                // 获取所有角色ID
                var roleIds = userRoles.Select(ur => ur.RoleId).Distinct().ToList();

                // 查询角色信息
                var roles = _roleRepository.GetListQuery()
                    .Where(r => roleIds.Contains(r.Id))
                    .ToList();

                // 构建用户ID到角色名称的映射
                var userRoleNames = new Dictionary<string, List<string>>();
                foreach (var userRole in userRoles)
                {
                    var role = roles.FirstOrDefault(r => r.Id == userRole.RoleId);
                    if (role != null)
                    {
                        if (!userRoleNames.ContainsKey(userRole.UserId))
                        {
                            userRoleNames[userRole.UserId] = new List<string>();
                        }
                        userRoleNames[userRole.UserId].Add(role.RoleNmae);
                    }
                }

                // 映射为UserListDto，密码字段固定为******
                var dtoPage = new Page<UserListDto>
                {
                    Items = result.Items.Select(u => new UserListDto
                    {
                        Id = u.Id,
                        Account = u.Account,
                        UserName = u.UserName,
                        NickName = u.NickName,
                        UserGender = u.UserGender,
                        MobilePhoneNumber = u.MobilePhoneNumber,
                        Telephone = u.Telephone,
                        Birthday = u.Birthday,
                        Email = u.Email,
                        DeptId = u.DeptId,
                        EmployeeNumber = u.EmployeeNumber,
                        IsOnLine = u.IsOnLine,
                        State = u.State,
                        LastLoginAt = u.LastLoginAt,
                        CreateTime = u.CreateTime,
                        Password = "******",
                        RoleNames = userRoleNames.ContainsKey(u.Id)
                            ? string.Join("、", userRoleNames[u.Id])
                            : null
                    }).ToList(),
                    PageNumber = result.PageNumber,
                    PageSize = result.PageSize,
                    TotalPages = result.TotalPages,
                    TotalItems = result.TotalItems
                };

                // 返回分页结果
                return ResponseReturnsEntity<Page<UserListDto>>.Success(dtoPage);
            }
            catch (Exception ex)
            {
                _logger.LogError($"分页查询用户列表失败: {ex.Message}");
                return ResponseReturnsEntity<Page<UserListDto>>.Fail($"查询失败: {ex.Message}");
            }
        }

        #endregion

        #region 业务
        /// <summary>
        /// 添加用户，并支持分配角色。操作包含事务，失败自动回滚。
        /// </summary>
        /// <param name="userRequest">用户信息及角色Id集合</param>
        /// <returns>操作结果，成功返回true，失败返回详细错误信息</returns>
        /// <remarks>
        /// 1. 支持同时为用户分配多个角色。
        /// 2. 用户和用户角色关联表(UserRole)的插入在同一事务中，任一失败均回滚。
        /// 3. 自动为主键Id赋值Guid字符串。
        /// 4. 捕获数据库异常和通用异常，记录详细日志。
        /// </remarks>
        public async Task<ResponseReturnsEntity<bool>> AddUser(UserRequest userRequest)
        {
            using var transaction = await _bunnyEaterContext.Database.BeginTransactionAsync();
            try
            {
                // 参数校验
                if (userRequest == null)
                {
                    return ResponseReturnsEntity<bool>.Fail("用户信息不能为空");
                }
                if (string.IsNullOrEmpty(userRequest.Account))
                {
                    return ResponseReturnsEntity<bool>.Fail("用户名不能为空");
                }
                if (string.IsNullOrEmpty(userRequest.Password))
                {
                    return ResponseReturnsEntity<bool>.Fail("密码不能为空");
                }

                // 1. 新增用户，自动分配主键Id
                var user = new User
                {
                    Id = Guid.NewGuid().ToString(),
                    Account = userRequest.Account,
                    Password = userRequest.Password, // 建议加密
                    UserName = userRequest.UserName,
                    NickName = userRequest.NickName,
                    UserGender = userRequest.UserGender,
                    MobilePhoneNumber = userRequest.MobilePhoneNumber,
                    Telephone = userRequest.Telephone,
                    Birthday = userRequest.Birthday,
                    Email = userRequest.Email,
                    DeptId = userRequest.DeptId,
                    EmployeeNumber = userRequest.EmployeeNumber,
                    IsOnLine = false,
                    State = userRequest.State,
                    LastLoginAt = DateTime.Now,
                    CreateTime = DateTime.Now
                };
                var userResult = await _userRepository.InsertEntityAsync(user);

                // 2. 新增用户角色关联（可分配多个角色）
                if (userRequest.RoleIds != null && userRequest.RoleIds.Any())
                {
                    var userRoles = userRequest.RoleIds.Select(roleId => new UserRole
                    {
                        Id = Guid.NewGuid().ToString(), // 自动分配主键Id
                        UserId = user.Id,
                        RoleId = roleId
                    }).ToList();

                    await _userRoleRepository.InsertEntityAsync(userRoles);
                }

                // 提交事务
                await transaction.CommitAsync();
                return ResponseReturnsEntity<bool>.Success(userResult > 0);
            }
            catch (DbUpdateException dbEx)
            {
                // 数据库异常，回滚事务并记录日志
                await transaction.RollbackAsync();
                _logger.LogError($"数据库更新异常，添加用户失败: {dbEx.Message}", dbEx);
                return ResponseReturnsEntity<bool>.Fail("数据库操作异常，添加用户失败，请检查数据有效性或联系管理员。");
            }
            catch (Exception ex)
            {
                // 其他异常，回滚事务并记录日志
                await transaction.RollbackAsync();
                _logger.LogError($"添加用户失败: {ex.Message}", ex);
                return ResponseReturnsEntity<bool>.Fail($"添加用户失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 修改
        /// </summary>
        public async Task<ResponseReturnsEntity<bool>> UptUser(UserRequest userRequest)
        {
            try
            {

                var user = userRequest.MapTo<User>();//映射用户表
                var result = await _userRepository.UpdateEntityAsync(user);//修改
                return result > 0 ? ResponseReturnsEntity<bool>.Success(result > 0) : ResponseReturnsEntity<bool>.Fail(result > 0);

            }
            catch (Exception ex)
            {
                // 记录日志
                _logger.LogError($"编辑用户失败,错误信息：【{ex.Message}】");
                //事务回滚
                await _bunnyEaterContext.Database.RollbackTransactionAsync();
                return ResponseReturnsEntity<bool>.Fail($"编辑用户失败,请联系管理员");
            }
        }

        /// <summary>
        /// 逻辑删除用户
        /// </summary>
        public async Task<ResponseReturnsEntity<bool>> DeleteUser(UserDto userDto)
        {
            try
            {
                var user = userDto.MapTo<User>();//映射用户表
                //var userIsExist = await _userRepository.GetEntityByIdAsync(user);//查询是否存在
                var userIsExist = await _userRepository.GetEntityAsync(x => x.Id == userDto.Id);
                if (!userIsExist)
                {
                    return ResponseReturnsEntity<bool>.Fail($"未找到用户：（{userDto.Account}），请检查");
                }

                var result = await _userRepository.DeleteByIdAsync(user);
                return result > 0 ? ResponseReturnsEntity<bool>.Success(true) : ResponseReturnsEntity<bool>.Fail(false);
            }
            catch (Exception ex)
            {
                // 记录日志
                _logger.LogError($"编辑用户状态失败,错误信息：【{ex.Message}】");
                //事务回滚
                await _bunnyEaterContext.Database.RollbackTransactionAsync();
                return ResponseReturnsEntity<bool>.Fail($"编辑用户状态失败,请联系管理员");
            }


        }
        /// <summary>
        /// 修改状态
        /// </summary>
        public async Task<ResponseReturnsEntity<bool>> UpdateUserState(UserRequest userDto)
        {
            var user = new User() { Id = userDto.Id };
            var entity = await _userRepository.GetEntityByIdAsync(user);
            if (entity == null) return ResponseReturnsEntity<bool>.Fail("用户不存在");
            if (entity.State == userDto.State)
            {
                string status = userDto.State ? "启用" : "禁用";
                return ResponseReturnsEntity<bool>.Fail($"当前状态已是{status}，请勿重复操作");
            }
            entity.State = userDto.State;
            var result = await _userRepository.UpdateEntityAsync(entity);
            return ResponseReturnsEntity<bool>.Success(result > 0);
        }

        /// <summary>
        /// 五表联查：获取用户及其角色和权限信息
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <returns>用户-角色-权限结构</returns>
        public async Task<UserRolePermissionDto> GetUserRolePermissions(string userId)
        {
            var user = await _userRepository.GetEntityByIdAsync(new User { Id = userId });
            if (user == null)
            {
                throw new InvalidOperationException($"未找到当前用户，请检查用户ID是否正确或用户是否已被删除");
            }

            // 用户角色
            var userRoles = _userRoleRepository.GetListQuery().Where(ur => ur.UserId == userId).ToList();
            var roleIds = userRoles.Select(ur => ur.RoleId).ToList();

            // 角色
            var roles = _roleRepository.GetListQuery().Where(r => roleIds.Contains(r.Id)).ToList();

            // 角色权限
            var rolePermissions = _rolePermissionsRepository.GetListQuery().Where(rp => roleIds.Contains(rp.RoleId)).ToList();
            var permissionIds = rolePermissions.Select(rp => rp.PermissionsId).Distinct().ToList();

            // 权限
            var permissions = _permissionsRepository.GetListQuery().Where(p => permissionIds.Contains(p.Id)).ToList();

            var result = new UserRolePermissionDto
            {
                UserId = user.Id,
                Account = user.Account,
                UserName = user.UserName,
                Roles = roles.Select(role => new RoleWithPermissionsDto
                {
                    RoleId = role.Id,
                    RoleNmae = role.RoleNmae,
                    Permissions = rolePermissions
                        .Where(rp => rp.RoleId == role.Id)
                        .Join(permissions, rp => rp.PermissionsId, p => p.Id, (rp, p) => new PermissionDto
                        {
                            PermissionsId = p.Id,
                            PermissionsName = p.PermissionsName,
                            PermissionsPath = p.PermissionsPath
                        }).ToList()
                }).ToList()
            };

            return result;
        }

        #endregion



    }
}
